/******************************************************************************
*
* Copyright (C), 2013, mophie. Co., Ltd. All Rights Reserved. 
*
* Version: v1.0.0
* $$Datae: 2013-7-24 
*
* Description:    
*   ADC API functions
*
* Function List: 
* 
* History:        
*         1. $$data:  2013-7-24
*            Author:  JPM team         
*
******************************************************************************/

/********include files********************************************************/
#include "adc_api.h"
#include "io_mgr.h"
#include "io_api.h"
#include "common_api.h"

/********global variables*****************************************************/
uint8_t adc_ch_list[ADC_TOTAL_CHANNEL_NUMS] = {
    ADC_CH_USBDP,
    ADC_CH_USBDM,
    ADC_CH_OVP,
    ADC_CH_CURRENT,
    ADC_CH_VOLTAGE
};

uint16_t adc_pdc_buf[ADC_TOTAL_CHANNEL_NUMS];
uint16_t adc_data_buf[ADC_TOTAL_CHANNEL_NUMS];
uint8_t  adc_ch_num[ADC_TOTAL_CHANNEL_NUMS];
uint8_t  adc_samp_times = 0;
uint8_t  samp_cnt = 0;
/********function list********************************************************/
/*****************************************************************************
** Function name:
**      adc_read_buffer
** Descriptions:
**      setup pdc for read adc datas 
**
** parameters:
**      p_adc----a pointer to ADC
**      p_s_buffer----destination buffer addr
**      ul_size----data length
**
** Returned value:
**      1----successful
**      0----failed
** 
*****************************************************************************/
uint32_t ADC_prepare_buffer(Adc * p_adc, uint16_t * p_s_buffer, uint32_t ul_size)
{
	/* Check if the first PDC bank is free. */
	if ((p_adc->ADC_RCR == 0) && (p_adc->ADC_RNCR == 0)) {
		p_adc->ADC_RPR = (uint32_t) p_s_buffer;
		p_adc->ADC_RCR = ul_size;
		p_adc->ADC_PTCR = ADC_PTCR_RXTEN;

		return 1;
	} else {	/* Check if the second PDC bank is free. */
		if (p_adc->ADC_RNCR == 0) {
			p_adc->ADC_RNPR = (uint32_t) p_s_buffer;
			p_adc->ADC_RNCR = ul_size;

			return 1;
		} else {
			return 0;
		}
	}
}

//void battery_samp_enable(void)
//{
//    PIO_set_bit(BATTERY_SAMP_PORT,BATTERY_SAMP_PIN_INDEX);
//}
//
//void battery_samp_disable(void)
//{
//    PIO_reset_bit(BATTERY_SAMP_PORT,BATTERY_SAMP_PIN_INDEX);
//}
//
//void ntc_samp_enable(void)
//{
//    PIO_reset_bit(NTC_SAMP_PORT,NTC_SAMP_PIN_INDEX);
//}
//
//void ntc_samp_disable(void)
//{
//    PIO_set_bit(NTC_SAMP_PORT,NTC_SAMP_PIN_INDEX);
//}

void ADC_set_sequence(Adc *p_adc, uint8_t* ch_list,
		uint8_t uc_num)
{
    uint8_t i;
    for(i=0;i<uc_num;i++)
    {
        if(ch_list[i] < 8)
        {
            p_adc->ADC_SEQR1 |= ch_list[i] << (4 * ch_list[i]);
        } 
        else if(ch_list[i] < 16)
        {
            p_adc->ADC_SEQR2 |= ch_list[i] << (4 * (ch_list[i]-8));
        }
    }
}
/*****************************************************************************
** Function name:
**      ADC_start_adc
** Descriptions:
**      Start adc 
**
** parameters:
**      NONE
**
** Returned value:
**      NONE
** 
*****************************************************************************/
void ADC_init_adc(void)
{	
    uint32_t i;
    
    // Enable peripheral clock. 
	pmc_enable_periph_clk(ID_ADC);
    
    //adc sample control pins config
    pmc_enable_periph_clk(ID_PIOA);
    pmc_enable_periph_clk(ID_PIOB);
    PIO_out_config_api(NTC_ENABLE_PIO, 0, 0, NTC_ENABLE_PIO_IDX);
    PIO_reset_bit(NTC_ENABLE_PIO, NTC_ENABLE_PIO_IDX);
    PIO_out_config_api(BP_ADC_ENABLE_PIO, 0, 0, BP_ADC_ENABLE_PIO_IDX);
    PIO_set_bit(BP_ADC_ENABLE_PIO, BP_ADC_ENABLE_PIO_IDX);
    
    //cpu_hz = ;
    
	// Initialize ADC, set adc clock and startup time. 
	adc_init(ADC, sysclk_get_cpu_hz(), ADC_CLOCK_FREQ, ADC_STARTUP_TIME);

	 // Set ADC tracking time,setting time ,transfer timing. 
	adc_configure_timing(ADC, ADC_TRACKING_TIME, ADC_SETTING_TIME, ADC_TRANSFER_TIME);

#ifdef ENABLE_ADC_TAG
    //Enable channel number tag. 
	adc_enable_tag(ADC);
#endif
    
	// Enable/disable sequencer. 
#ifdef ADC_SEQUENCE_ENABLE
	// Set user defined channel sequence. 
    ADC_set_sequence(ADC,adc_ch_list,ADC_TOTAL_CHANNEL_NUMS);
        
	//Enable sequencer. 
	adc_start_sequencer(ADC);

	// Enable channels. 
	for (i = 0; i < ADC_TOTAL_CHANNEL_NUMS; i++) {
		adc_enable_channel(ADC, adc_ch_list[i]);
	}
	// Update channel number.
        common_mem_cpy(adc_ch_list, adc_ch_num, ADC_TOTAL_CHANNEL_NUMS);
    /*for(i=0;i<ADC_TOTAL_CHANNEL_NUMS;i++){ 
        adc_ch_num[i] = adc_ch_list[i];
    }*/
	
#else
	// Disable sequencer. 
	adc_stop_sequencer(ADC);

	// Enable channels. 
	adc_enable_channel(ADC, ADC_CH_USBDP);
	adc_enable_channel(ADC, ADC_CH_USBDM);
	adc_enable_channel(ADC, ADC_CH_OVP);
	adc_enable_channel(ADC, ADC_CH_CURRENT);
	adc_enable_channel(ADC, ADC_CH_VOLTAGE);
	// Update channel number.
        common_mem_cpy(adc_ch_list, adc_ch_num, ADC_TOTAL_CHANNEL_NUMS); 
    /*for(i=0;i<ADC_TOTAL_CHANNEL_NUMS;i++){ 
        adc_ch_num[i] = adc_ch_list[i];
    }*/
#endif

	// Set gain and offset (only single ended mode used here). 
	adc_disable_anch(ADC);	// Disable analog change. 
	adc_set_channel_input_gain(ADC, ADC_CH_USBDP, ADC_GAINVALUE_0);

	adc_disable_channel_input_offset(ADC, ADC_CH_USBDP);
    
#ifdef ADC_POWER_SAVE    
	// Set power save. 
	adc_configure_power_save(ADC, 1, 0);
#else 
	adc_configure_power_save(ADC, 0, 0);
#endif
    
	// Transfer with/without PDC.
#ifdef ADC_PDC_ENABLE 
	ADC_prepare_buffer(ADC, adc_pdc_buf, ADC_BUFFER_SIZE);
	// Enable PDC channel interrupt. 
	//adc_enable_interrupt(ADC, ADC_IER_RXBUFF);
#else 
	// Enable Data ready interrupt. 
	//adc_enable_interrupt(ADC, ADC_IER_DRDY);
#endif
    
	// Enable ADC interrupt. 
	//NVIC_EnableIRQ(ADC_IRQn);

	// Configure trigger mode,Disable hardware trigger.
	adc_configure_trigger(ADC, ADC_TRIG_SW, 0); 
}

bool get_adc_result(bool b_force_reset)
{
    uint8_t i;
    
    //static uint16_t low_volt = 0xffff, high_volt = 0;
   // uint16_t ave_6;
    
    if(b_force_reset)
    {
        samp_cnt = 0;
    }
    
    while((adc_get_status(ADC) & ADC_ISR_RXBUFF) != ADC_ISR_RXBUFF);
    ADC_prepare_buffer(ADC, adc_pdc_buf, ADC_BUFFER_SIZE);
    /*if(b_force_reset)
    {
        return false;
    }*/
    
    for(i=0;i<ADC_TOTAL_CHANNEL_NUMS;i++)
    {
      adc_pdc_buf[i] &= ADC_LCDR_LDATA_Msk;
    }
    
    /*if(adc_pdc_buf[4] < low_volt)
    {
        low_volt = adc_pdc_buf[4];
    }
    if(adc_pdc_buf[4] > high_volt)
    {
        high_volt = adc_pdc_buf[4];
    }*/
    
    if(samp_cnt == 0)
    {
        //common_mem_cpy(adc_pdc_buf, adc_data_buf, ADC_TOTAL_CHANNEL_NUMS);
        for(i=0;i<ADC_TOTAL_CHANNEL_NUMS;i++)
        {
            adc_data_buf[i]= adc_pdc_buf[i];
        }
    }
    else
    {
        for(i=0;i<ADC_TOTAL_CHANNEL_NUMS;i++)
        {
            adc_data_buf[i] += adc_pdc_buf[i];
        }
    }
    samp_cnt++;
    
    if(samp_cnt == 8)
    {
        /*for(i=0;i<ADC_TOTAL_CHANNEL_NUMS;i++)
        {
            adc_data_buf[i] /= 8;
        }*/
        /*adc_data_buf[4] -= low_volt;
        adc_data_buf[4] -= high_volt;
        ave_6 = adc_data_buf[4] / 6;
        adc_data_buf[4] += ave_6;
        adc_data_buf[4] += ave_6;
        
        low_volt = 0xffff;
        high_volt = 0;*/
          
        samp_cnt = 0;
        
        return true;
    }
    
    return false;
}

//get d+ voltage
/*uint16_t get_d_plus_volt(void)
{
    return(adc_data_buf[1]);
}*/

//get d- voltage
/*uint16_t get_d_minus_volt(void)
{
    return(adc_data_buf[0]);
}*/

//get current value to iPhone
/*uint16_t get_cur(void)
{
    return(adc_data_buf[4]);
}*/

//get current value to iPhone
/*uint16_t get_battery_volt(void)
{
    return(adc_data_buf[3]);
}*/

//get input voltage
/*uint16_t get_input_voltage(void)
{
    return(adc_data_buf[2]);
}*/

/*void start_check_adc(void)
{
    //config adc on battery power detect
    adc_start(ADC);
}*/

void reset_check_adc(void)
{
    while((adc_get_status(ADC) & ADC_ISR_RXBUFF) != ADC_ISR_RXBUFF);
    ADC_prepare_buffer(ADC, adc_pdc_buf, ADC_BUFFER_SIZE);
    samp_cnt = 0;
    adc_start(ADC);
}


